package org.summer.lawyer.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.summer.common.core.constant.UserConstants;
import org.summer.common.core.exception.ServiceException;
import org.summer.common.core.utils.MapstructUtils;
import org.summer.common.mybatis.core.page.PageQuery;
import org.summer.common.mybatis.core.page.TableDataInfo;
import org.summer.common.satoken.utils.LoginHelper;
import org.summer.lawyer.constant.SystemConstants;
import org.summer.lawyer.domain.WxUser;
import org.summer.lawyer.domain.bo.wxuser.WxUserBo;
import org.summer.lawyer.domain.vo.wxuser.*;
import org.summer.lawyer.event.WxUserRegisterEvent;
import org.summer.lawyer.mapper.WxUserMapper;
import org.summer.lawyer.service.IWxUserService;
import org.summer.lawyer.util.ParamsUtil;
import org.summer.system.domain.bo.SysDictDataBo;
import org.summer.system.domain.vo.SysDictDataVo;
import org.summer.system.domain.vo.SysUserVo;
import org.summer.system.service.ISysDictDataService;
import org.summer.system.service.ISysUserService;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 *
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class WxUserServiceImpl extends ServiceImpl<WxUserMapper, WxUser> implements IWxUserService, ApplicationEventPublisherAware {

    private final ISysDictDataService sysDictDataService;

    private final ISysUserService sysUserService;

    /**
     * 查询微信用户信息
     *
     * @param wxUserId 主键
     * @return 微信用户信息
     */
    @Override
    public WxUserVo selectWxUserVoById(Long wxUserId) {
        return baseMapper.selectVoById(wxUserId);
    }

    /**
     * 分页查询微信用户信息列表
     *
     * @param vo        查询条件
     * @param pageQuery 分页参数
     * @return 微信用户信息分页列表
     */
    @Override
    public TableDataInfo<WxUserVo> selectPageList(WxUserVo vo, PageQuery pageQuery) {
        LambdaQueryWrapper<WxUser> lqw = buildQueryWrapper(vo);
        Page<WxUserVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    private LambdaQueryWrapper<WxUser> buildQueryWrapper(WxUserVo vo) {
        Map<String, Object> params = ParamsUtil.getParams(vo.getParams());
        LambdaQueryWrapper<WxUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(StrUtil.isNotBlank(vo.getAccount()), WxUser::getAccount, vo.getAccount());
        lqw.eq(StrUtil.isNotBlank(vo.getPassword()), WxUser::getPassword, vo.getPassword());
        lqw.like(StrUtil.isNotBlank(vo.getNickname()), WxUser::getNickname, vo.getNickname());
        lqw.eq(StrUtil.isNotBlank(vo.getAvatar()), WxUser::getAvatar, vo.getAvatar());
        lqw.eq(StrUtil.isNotBlank(vo.getOpenId()), WxUser::getOpenId, vo.getOpenId());
        lqw.eq(StrUtil.isNotBlank(vo.getUnionId()), WxUser::getUnionId, vo.getUnionId());
        lqw.eq(StrUtil.isNotBlank(vo.getWxUserType()), WxUser::getWxUserType, vo.getWxUserType());
        lqw.like(StrUtil.isNotBlank(vo.getPhoneNumber()), WxUser::getPhoneNumber, vo.getPhoneNumber());
        lqw.like(StrUtil.isNotBlank(vo.getRealName()), WxUser::getRealName, vo.getRealName());
        lqw.eq(StrUtil.isNotBlank(vo.getSex()), WxUser::getSex, vo.getSex());
        lqw.eq(StrUtil.isNotBlank(vo.getStatus()), WxUser::getStatus, vo.getStatus());
        lqw.eq(vo.getAgreement() != null, WxUser::getAgreement, vo.getAgreement());
        lqw.eq(StrUtil.isNotBlank(vo.getRealNameAuth()), WxUser::getRealNameAuth, vo.getRealNameAuth());
        lqw.eq(StrUtil.isNotBlank(vo.getOpeningBank()), WxUser::getOpeningBank, vo.getOpeningBank());
        lqw.eq(StrUtil.isNotBlank(vo.getBankAccount()), WxUser::getBankAccount, vo.getBankAccount());
        lqw.eq(StrUtil.isNotBlank(vo.getBankAddress()), WxUser::getBankAddress, vo.getBankAddress());
        lqw.like(StrUtil.isNotBlank(vo.getCardName()), WxUser::getCardName, vo.getCardName());
        lqw.like(StrUtil.isNotBlank(vo.getUserTag()),WxUser::getUserTag, vo.getUserTag());
        lqw.eq(StrUtil.isNotBlank(vo.getCardPhone()), WxUser::getCardPhone, vo.getCardPhone());
        lqw.between(params.get("beginTime") != null && params.get("endTime") != null, WxUser::getCreateTime, params.get("beginTime"), params.get("endTime"));
        return lqw;
    }

    @Override
    public WxUserVo selectByPhoneNumber(String phoneNumber, String wxUserType) {
        LambdaQueryWrapper<WxUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WxUser::getPhoneNumber, phoneNumber)
                .eq(WxUser::getWxUserType, wxUserType);
        return baseMapper.selectVoOne(queryWrapper, false);
    }

    @Override
    public void saveByPhoneNumber(WxUserCreateVo vo) {
        WxUser wxUser = new WxUser();
        WxUserVo wxUserVo = selectByPhoneNumber(vo.getPhoneNumber(), vo.getWxUserType());
        if (ObjectUtil.isNull(wxUserVo)) {
            MapstructUtils.convert(vo, wxUser);
            wxUser.setStatus(UserConstants.USER_NORMAL);
            wxUser.setCreateTime(DateUtil.date());
            wxUser.setUpdateTime(DateUtil.date());
            this.save(wxUser);
            vo.setWxUserId(wxUser.getWxUserId());
            //发送消息
            wxUserVo = selectWxUserVoById(vo.getWxUserId());
            applicationEventPublisher.publishEvent(new WxUserRegisterEvent(this, wxUserVo));
        }
    }

    @Override
    public void createWxUser(WxUserCreateVo vo) {
        WxUser wxUser = new WxUser();
        wxUser.setStatus(UserConstants.USER_NORMAL);
        MapstructUtils.convert(vo, wxUser);
        wxUser.setCreateTime(DateUtil.date());
        wxUser.setUpdateTime(DateUtil.date());
        baseMapper.insert(wxUser);
        vo.setWxUserId(wxUser.getWxUserId());
        WxUserVo wxUserVo = selectWxUserVoById(wxUser.getWxUserId());
        applicationEventPublisher.publishEvent(new WxUserRegisterEvent(this, wxUserVo));
    }

    /**
     * 校验用户名称是否唯一
     *
     * @param vo 用户信息
     * @return 结果
     */
    @Override
    public boolean checkAccountUnique(WxUserVo vo) {
        return baseMapper.exists(new LambdaQueryWrapper<WxUser>()
                .eq(WxUser::getAccount, vo.getAccount())
                .ne(ObjectUtil.isNotNull(vo.getWxUserId()), WxUser::getWxUserId, vo.getWxUserId()));
    }

    /**
     * 校验手机号码是否唯一
     *
     * @param vo 用户信息
     */
    @Override
    public boolean checkPhoneUnique(WxUserVo vo) {
        return baseMapper.exists(new LambdaQueryWrapper<WxUser>()
                .eq(WxUser::getPhoneNumber, vo.getPhoneNumber())
                .ne(ObjectUtil.isNotNull(vo.getWxUserId()), WxUser::getWxUserId, vo.getWxUserId()));
    }

    @Override
    public List<WxUserMiniAppVo> buildWxUserMiniAppList(String openId) {
        if (StrUtil.isEmpty(openId)) {
            return CollUtil.newArrayList();
        }
        List<WxUserMiniAppVo> list = JSONUtil.toList(openId, WxUserMiniAppVo.class);
        return list;
    }

    @Override
    public void updateWxUserOpenId(WxUserVo vo) {
        WxUser wxUser = baseMapper.selectById(vo.getWxUserId());
        if (wxUser != null) {
            LambdaUpdateWrapper<WxUser> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.eq(WxUser::getWxUserId, wxUser.getWxUserId())
                    .set(WxUser::getOpenId, vo.getOpenId())
                    .set(StrUtil.isNotBlank(vo.getUnionId()), WxUser::getUnionId, vo.getUnionId());
            baseMapper.update(updateWrapper);
        }
    }

    @Override
    public WxUserVo selectWxUserById(Long wxUserId) {
        return baseMapper.selectVoById(wxUserId);
    }

    @Override
    public void updateAccount(AccountUpdateVo vo) {
        WxUser wxUser = baseMapper.selectById(vo.getWxUserId());
        if (ObjectUtil.isNull(wxUser)) {
            throw new ServiceException("未找到用户信息");
        }
        LambdaUpdateWrapper<WxUser> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(WxUser::getWxUserId, vo.getWxUserId())
                .set(WxUser::getNickname, vo.getNickname())
                .set(WxUser::getPhoneNumber, vo.getPhoneNumber())
                .set(WxUser::getSex, vo.getSex())
                .set(WxUser::getAvatar, vo.getAvatar());

        baseMapper.update(updateWrapper);
    }

    @Override
    public WxUserVo selectWxUserByAccount(String account) {
        return baseMapper.selectVoOne(new LambdaQueryWrapper<WxUser>().eq(WxUser::getAccount, account));
    }

    @Override
    public void resetPassword(WxUserVo vo) {
        LambdaUpdateWrapper<WxUser> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(WxUser::getWxUserId, vo.getWxUserId())
                .set(WxUser::getPassword, BCrypt.hashpw(vo.getPassword()));
        baseMapper.update(updateWrapper);
    }

    /**
     * 校验并批量删除微信用户信息信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public CustomerServiceVo selectCustomerServiceVo() {
        CustomerServiceVo vo = new CustomerServiceVo();
        SysDictDataBo dictDataBo = new SysDictDataBo();
        dictDataBo.setDictType(SystemConstants.SERVICE_HOTLINE);
        List<SysDictDataVo> dictDataVoList = sysDictDataService.selectDictDataList(dictDataBo);
        if (CollUtil.isNotEmpty(dictDataVoList)) {
            for (SysDictDataVo dataVo : dictDataVoList) {
                if (CustomerServiceVo.TEL.equals(dataVo.getDictLabel())) {
                    vo.setTel(dataVo.getDictValue());
                } else if (CustomerServiceVo.WORK_TIME.equals(dataVo.getDictLabel())) {
                    vo.setWorkTime(dataVo.getDictValue());
                } else if (CustomerServiceVo.DESC.equals(dataVo.getDictLabel())) {
                    vo.setDesc(dataVo.getDictValue());
                }
            }
        }
        return vo;
    }

    @Override
    public void saveCustomerService(CustomerServiceVo vo) {
        CustomerServiceVo customerServiceVo = new CustomerServiceVo();
        SysDictDataBo dictDataBo = new SysDictDataBo();
        dictDataBo.setDictType(SystemConstants.SERVICE_HOTLINE);
        List<SysDictDataVo> dictDataVoList = sysDictDataService.selectDictDataList(dictDataBo);
        if (CollUtil.isNotEmpty(dictDataVoList)) {
            for (SysDictDataVo dataVo : dictDataVoList) {
                if (CustomerServiceVo.TEL.equals(dataVo.getDictLabel())) {
                    dataVo.setDictValue(customerServiceVo.getTel());
                } else if (CustomerServiceVo.WORK_TIME.equals(dataVo.getDictLabel())) {
                    dataVo.setDictValue(vo.getWorkTime());
                } else if (CustomerServiceVo.DESC.equals(dataVo.getDictLabel())) {
                    dataVo.setDictValue(vo.getDesc());
                }
                SysDictDataBo dataBo = new SysDictDataBo();
                BeanUtils.copyProperties(dataVo, dataBo);
                sysDictDataService.updateDictData(dataBo);
            }
        }
        //删除全部客服
        SysDictDataBo dictChatUserDataBo = new SysDictDataBo();
        dictChatUserDataBo.setDictType(SystemConstants.CHAT_USER);
        List<SysDictDataVo> dictDataVos = sysDictDataService.selectDictDataList(dictChatUserDataBo);
        Long[] delIds = ArrayUtil.newArray(Long.class, dictDataVos.size());
        int i = 0;
        for (SysDictDataVo dictDataVo : dictDataVos) {
            delIds[i] = dictDataVo.getDictCode();
            i++;
        }
        if (delIds.length > 0) {
            sysDictDataService.deleteDictDataByIds(delIds);
        }
        for (String chatId : vo.getChatIds()) {
            SysUserVo sysUserVo = sysUserService.selectUserById(Long.parseLong(chatId));
            if (sysUserVo != null) {
                SysDictDataBo newDictDataBo = new SysDictDataBo();
                newDictDataBo.setDictType(SystemConstants.CHAT_USER);
                newDictDataBo.setDictValue(String.valueOf(sysUserVo.getUserId()));
                newDictDataBo.setDictLabel(sysUserVo.getNickName());
                sysDictDataService.insertDictData(newDictDataBo);
            }
        }
    }

    @Override
    public List<ChatUserVo> selectListChatUser() {
        List<ChatUserVo> chatUserVos = CollUtil.newArrayList();
        SysDictDataBo dictDataBo = new SysDictDataBo();
        dictDataBo.setDictType(SystemConstants.CHAT_USER);
        List<SysDictDataVo> dictDataVos = sysDictDataService.selectDictDataList(dictDataBo);
        if (CollUtil.isNotEmpty(dictDataVos)) {
            for (SysDictDataVo dictDataVo : dictDataVos) {
                ChatUserVo chatUserVo = new ChatUserVo();
                chatUserVo.setChatId(dictDataVo.getDictValue());
                chatUserVo.setChatName(dictDataVo.getDictLabel());
                chatUserVos.add(chatUserVo);
            }
        }
        return chatUserVos;
    }

    @Override
    public void changeWxUserStatus(WxUserVo vo) {
        LambdaUpdateWrapper<WxUser> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(WxUser::getWxUserId, vo.getWxUserId())
                .set(WxUser::getUpdateTime, DateUtil.date())
                .set(LoginHelper.getUserId() != null, WxUser::getUpdateBy, LoginHelper.getUserId())
                .set(WxUser::getStatus, vo.getStatus());
        baseMapper.update(updateWrapper);
    }

    @Override
    public void updateWxUserTag(WxUserBo bo) {
        LambdaUpdateWrapper<WxUser> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(WxUser::getWxUserId, bo.getWxUserId());
        WxUser wxUser = new WxUser();
        wxUser.setWxUserId(bo.getWxUserId());
        wxUser.setUserTag(bo.getUserTag());
        wxUser.setUpdateTime(DateUtil.date());
        if (LoginHelper.getUserId() != null) {
            wxUser.setUpdateBy(LoginHelper.getUserId());
        }
        baseMapper.update(wxUser, updateWrapper);
    }

    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}
